using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;

namespace Microsoft.SharedSource.SqlServer.MDDE.ManagementStudio
{
    internal static class UIHelper
    {
        #region Changes xml generation methods.
        internal static XmlDocument CreateChangesXmlInstance()
        {
            XmlDocument changesXml = new XmlDocument();
            XmlElement instanceRoot =
                changesXml.CreateElement("PackageChanges");
            changesXml.AppendChild(instanceRoot);
            return changesXml;
        }

        internal static XmlNode AppendComponent(
            XmlElement xRootElement, string componentType,
            string componentName, string componentUri)
        {
            XmlNode instanceComponent;

            // Check if we already have this component into our instance data.
            // If not, add it.
            switch (componentType)
            {
                case "Component":
                case "Variable":
                case "ConnectionManager":
                    instanceComponent =
                        xRootElement.SelectSingleNode(
                        "//" + componentType +
                        "[@URL=\"" + componentUri + "\"]");

                    if (instanceComponent == null)
                        instanceComponent =
                            AppendChildElement(
                            xRootElement,
                            componentType,
                            new string[] { 
                                "Name",componentName,
                                "URL",componentUri
                            });
                    break;
                default:
                    return null;
            }

            return instanceComponent;
        }

        internal static void AppendComponentProperty(XmlElement xRootElement,
            string componentName, string componentType, string componentUri,
            string scalarPropertyName, string scalarPropertyValue)
        {
            XmlNode instanceComponent =
                AppendComponent(xRootElement, componentType,
                componentName, componentUri);

            // Check if we have the 'Properties' node in instance data.
            XmlNode xProperties =
                instanceComponent.SelectSingleNode("./Properties");
            // If not, add it.
            if (xProperties == null)
                xProperties =
                    AppendChildElement(
                    instanceComponent,
                    "Properties", null);

            // Add in the 'Property' nodes.
            XmlNode instanceProperty =
                xProperties.SelectSingleNode(
                "./Property[@Name=\"" + scalarPropertyName + "\"]");

            // If not add it.
            if (instanceProperty == null)
                instanceProperty =
                    AppendChildElement(
                    xProperties,
                    "Property",
                    new string[] { 
                        "Name", scalarPropertyName, 
                        "Value", scalarPropertyValue });

            // If the property value is null, remove the property element.
            if (scalarPropertyValue == null)
            {
                instanceProperty.ParentNode.RemoveChild(instanceProperty);

                // if the component node does not have any child, remove it.
                if (instanceComponent.ChildNodes.Count == 0)
                    instanceComponent.ParentNode.
                        RemoveChild(instanceComponent);
            }
            else
                // Update the property value.
                instanceProperty.Attributes["Value"].Value =
                    scalarPropertyValue;
        }

        internal static void AppendMapping(XmlElement xRootElement,
            string componentName, string componentType, string componentUri,
            string sourceColumnName, bool sourceColumnUsage,
            string destinationColumnName)
        {
            XmlNode instanceComponent =
                AppendComponent(xRootElement, componentType,
                componentName, componentUri);

            // Check if we have the 'Mappings' node in instance data.
            XmlNode xMappings =
                instanceComponent.SelectSingleNode("./Mappings");
            // If not, add it.
            if (xMappings == null)
                xMappings =
                    AppendChildElement(
                    instanceComponent,
                    "Mappings", null);

            // Check if we have the changed mapping in instance data.
            // Assumption: Taking the source column name as the key for search.
            XmlNode instanceMapping = xMappings.SelectSingleNode(
                "./Mapping[@SourceColumn=\"" +
                sourceColumnName + "\"]");

            // If not add it.
            if (instanceMapping == null)
                instanceMapping =
                    AppendChildElement(
                    xMappings,
                    "Mapping",
                    new string[] { 
                        "Usage", sourceColumnUsage ? "True" : "False",
                        "SourceColumn", sourceColumnName,
                        "DestinationColumn",destinationColumnName
                    });
        }

        internal static XmlNode AppendCollection(XmlElement xRootElement,
            string componentName, string componentType, string componentUri,
            string columnCollectionType, string columnCollectionName)
        {
            // Locate the configurable component.
            XmlNode xnodeConfigurableComponent =
                AppendComponent(xRootElement, componentType,
                componentName, componentUri);

            // Locate the 'CollectionInformation' element.
            XmlNode xCollectionInformation =
                xnodeConfigurableComponent.SelectSingleNode(
                "./CollectionInformation");

            if (xCollectionInformation == null)
                xCollectionInformation =
                    AppendChildElement(
                    xnodeConfigurableComponent, "CollectionInformation", null);

            // Locate the 'Collection' element.
            XmlNode xnodeCollection =
                xCollectionInformation.SelectSingleNode(
                "./Collection[@Type=\"" + columnCollectionType +
                "\" and @Name=\"" + columnCollectionName + "\"]");

            // Create a 'Collection' element.
            if (xnodeCollection == null)
                xnodeCollection =
                    AppendChildElement(
                    xCollectionInformation,
                    "Collection",
                    new string[] {
                        "Name", columnCollectionName,
                        "Type", columnCollectionType
                    });
            return xnodeCollection;
        }

        internal static void AppendColumnCollectionProperty(
            XmlElement xRootElement, string componentName, string componentType,
            string componentUri, string columnCollectionType,
            string columnCollectionName, string scalarPropertyName,
            string scalarPropertyValue)
        {
            XmlNode xnodeCollection =
                AppendCollection(xRootElement,
                componentName, componentType, componentUri,
                columnCollectionType, columnCollectionName);

            // Check if we have the 'Properties' node in instance data.
            XmlNode xProperties =
                xnodeCollection.SelectSingleNode("./Properties");
            // If not, add it.
            if (xProperties == null)
                xProperties =
                    AppendChildElement(
                    xnodeCollection,
                    "Properties", null);

            // Add in the 'Property' nodes.
            XmlNode instanceProperty =
                xProperties.SelectSingleNode(
                "./Property[@Name=\"" + scalarPropertyName + "\"]");

            // If not add it.
            if (instanceProperty == null)
                AppendChildElement(
                xProperties,
                "Property",
                new string[] { 
                        "Name", scalarPropertyName,
                        "Value", scalarPropertyValue });
        }

        internal static void AppendColumnProperty(
            XmlElement xRootElement, string componentName, string componentType,
            string componentUri, string columnCollectionType,
            string columnCollectionName, string columnName,
            string scalarPropertyName, string scalarPropertyValue)
        {
            XmlNode xnodeCollection =
                AppendCollection(xRootElement,
                componentName, componentType, componentUri,
                columnCollectionType, columnCollectionName);

            // Check if we have the 'Columns' node in instance data.
            XmlNode xColumns =
                xnodeCollection.SelectSingleNode("./Columns");
            // If not, add it.
            if (xColumns == null)
                xColumns =
                    AppendChildElement(
                    xnodeCollection,
                    "Columns", null);

            // Locate the 'Column' element.
            XmlNode xColumn =
                xColumns.SelectSingleNode(
                "./Column[@Name=\"" + columnName + "\"]");

            // Create a 'Column' element, if not found.
            if (xColumn == null)
                xColumn =
                    AppendChildElement(
                    xColumns,
                    "Column",
                    new string[] { 
                    "Name", columnName
                });

            // Check if we have the 'Properties' node in instance data.
            XmlNode xProperties =
                xColumn.SelectSingleNode("./Properties");

            // If not, add it.
            if (xProperties == null)
                xProperties =
                    AppendChildElement(
                    xColumn,
                    "Properties", null);

            // Add in the 'Property' nodes.
            XmlNode instanceProperty =
                xProperties.SelectSingleNode(
                "./Property[@Name=\"" + scalarPropertyName + "\"]");

            // If not add it.
            if (instanceProperty == null)
                AppendChildElement(
                xProperties,
                "Property",
                new string[] { 
                        "Name", scalarPropertyName, 
                        "Value", scalarPropertyValue });
        }

        #endregion

        #region General xml document management methods.

        internal static XmlElement AppendChildElement(XmlNode parentElement,
            string childelementName, string[] attributeFollowedByValue)
        {
            return AppendChildElement(
                parentElement, childelementName,
                null, attributeFollowedByValue);
        }

        internal static XmlElement AppendChildElement(XmlNode parentElement,
            string childelementName, string innerXml,
            string[] attributeFollowedByValue)
        {
            XmlElement childElement;
            if (parentElement is XmlDocument)
                // Special treatment for XmlDocument.
                childElement =
                    ((XmlDocument)parentElement).
                    CreateElement(childelementName);
            else
                childElement =
                    parentElement.OwnerDocument.
                    CreateElement(childelementName);

            parentElement.AppendChild(childElement);

            if (!string.IsNullOrEmpty(innerXml))
                childElement.InnerXml = innerXml;

            AppendAttribute(childElement, attributeFollowedByValue);

            return childElement;
        }

        internal static void AppendAttribute(XmlElement parentElement,
            string[] attributeFollowedByValue)
        {
            if (attributeFollowedByValue == null)
                return;

            for (int i = 0; i < attributeFollowedByValue.Length; i++)
            {
                XmlAttribute attrib =
                    parentElement.OwnerDocument.
                    CreateAttribute(attributeFollowedByValue[i]);
                parentElement.Attributes.Append(attrib);

                i++;

                attrib.Value =
                    (i >= attributeFollowedByValue.Length) ?
                    string.Empty : attributeFollowedByValue[i];
            }
        }

        #endregion
    }
}
